package com.example.forum_system.searchEngine.wordList;

import com.example.forum_system.searchEngine.exception.SearchEngineException;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * @BelongsProject: 0.forum_system
 * @BelongsPackage: com.example.forum_system.SE
 * @Author : 游在海里的鱼
 * @CreateTime : 2023-11-26  20:20
 * @Version : 1.0
 * @Description : 单词表
 */

/*-------------------------------------------------------------------- 
    单词表，最核心的部分，一个（词-索引列表）的哈希表
    下面是给出的一个案例：
    ------------------------------------------------
    | 词    | 词索引列表WordIndexList（ID-位置1/位置2） |
    |----------------------------------------------|
    | hello |   （1-1），（2-21/15），（4-12/12/23）  |
    |----------------------------------------------|
    | b     |   （1-12），（2-21/15），（5-12/12/23） |
    ------------------------------------------------
        词是每篇文章的最基础单位，所有文章都由词来构成。所以，对于一篇文章，
    我们将其中出现的所有词都记录在单词表中，记录下这个词出现在那篇文章（ID）
    和文章的那些位置。
        比如，ID为1的文章记录有“hello word”，单词表里，“hello”这个词里
    就会添加上（1-1）表示ID为1的文章里的第一个词是hello。
*/
    
/*------------------------------------------------------------------- 
    文章id集合表，一个哈希表（词-文章id集合）
    下面是给出的一个案例：
    ---------------------
    | 词    | 文章ID集合  |
    |--------------------
    | hello |   1，2，4  |
    |--------------------
    | b     |   1，2，5  |
    ---------------------
        文章ID集合保存了此词下，保存的所有文章的ID。因为在词索引列表中id作
    为元素下标，其中会有很多被删除了的无效元素。使用这个集合能提高遍历的效率，
    直接跳过无效元素的下标。
 */
    
@Slf4j
public class WordList {

    //单词表，是一个哈希表（词-词索引列表）
    private Map<String, WordIndexList> word_indexList = new HashMap<>();
    //文章id集合表，这是一个哈希表（词-文章id集合）
    private Map<String, Set<Integer>> word_idSet = new HashMap<>();

    
    /*------------------------------------普--通--方--法------------------------------------------------------------------
     * @Desc  : 添加词索引进此词的单词表中
     * @Param : [word, articleId, location]
     * @Return: boolean
    **/
    public boolean addIndex(String word,int articleId,int location){
        //1.得到此词下的词索引列表
        WordIndexList indexList = word_indexList.get(word);
        //2.若此词下的词索引列表为空，则新建“word-wordIndexList”,"word-idSet"进哈希表
        if(indexList == null){
            indexList = new WordIndexList();
            word_indexList.put(word,indexList);
            word_idSet.put(word,new TreeSet<Integer>());
        }
        //3.给wordIndexList和idSet中添加新的元素
        indexList.add(articleId,location);
        word_idSet.get(word).add(articleId);
        return true;
    }

    /*------------------------------------普--通--方--法------------------------------------------------------------------
     * @Desc  : 删除此词下的词索引
     * @Param : [word, articleId]
     * @Return: boolean
    **/
    public boolean removeIndex(String word,int articleId) throws Exception {
        //1.得到此词下的词索引列表
        WordIndexList indexList = word_indexList.get(word);
        //2.此词下的词索引为空，出现异常情况则抛出
        if(indexList == null){
            log.error("key不存在");
            throw new SearchEngineException("key doesn't exist");
        }
        //3.删除词索引
        indexList.remove(articleId);
        //4.删除id
        word_idSet.get(word).remove(articleId);
        //5.返回删除成功
        return true;
    }

    /*------------------------------------普--通--方--法------------------------------------------------------------------
     * @Desc  : 获取此词下的，此文章id的词索引
     * @Param : [word, articleId]
     * @Return: com.example.forum_system.searchEngine.wordList.WordIndex
    **/
    public WordIndex getIndex(String word, int articleId) throws Exception {
        //1.得到此词下的词索引列表
        WordIndexList indexList = word_indexList.get(word);
        //2.此词下的词索引为空，出现异常情况则抛出
        if(indexList == null){
            log.error("key不存在");
            throw new SearchEngineException("key doesn't exist");
        }
        //3.返回此词下，此id的词索引
        return indexList.get(articleId);
    }

    /*------------------------------------普--通--方--法------------------------------------------------------------------
     * @Desc  : 此词下，是否存在某文章
     * @Param : [word, articleId]
     * @Return: boolean
    **/
    public boolean hasArticle(String word, int articleId){
        //1.得到此词下的文章id集合
        Set<Integer> set = word_idSet.get(word);
        //2.集合为空则不存在
        if(set == null){
            return false;
        }
        //3.集合中是否包含此文章id
        return set.contains(articleId);
    }

    /*------------------------------------普--通--方--法------------------------------------------------------------------
     * @Desc  : 获得此词所有的文章id集合
     * @Param : [word]
     * @Return: java.util.Set<java.lang.Integer>
    **/
    public Set<Integer> getSet(String word){
        //1.得到此词下的文章id集合
        Set<Integer> set = word_idSet.get(word);
        //2.集合为空则新建一个空集合用于返回，表示无元素
        if(set == null){
            return new TreeSet<>();
        }
        //3.返回集合
        return set;
    }
}
